home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
msdos
/
raytrace
/
pov
/
gen
/
geodome
/
geodome.c
next >
Wrap
C/C++ Source or Header
|
1994-04-28
|
9KB
|
412 lines
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRIANGLE 1
#define MESH 2
#define ERROR -1
#define VERSION 1
#define INCREMENT 1
#define EMAIL_ADDRESS "abw@oasis.icl.co.uk"
/*
* geodome.c
*
* (C) 1994 Andy Wardley (abw@oasis.icl.co.uk). All Rights Reserved.
*
* maths libraray is required.
* getopt must be provided.
*
*/
struct vertex { double x, y, z; };
struct triangle { struct vertex a, b, c; };
struct edge
{
struct vertex a, b;
struct edge *next;
};
struct joint
{
struct vertex v;
struct joint *next;
};
/* default options */
int mode = TRIANGLE;
int rec_depth = 3;
double pipe_radius = 0.01;
double joint_radius = 0.015;
double geodome_radius = 1;
/* heads of linked lists */
struct edge *first_edge;
struct joint *first_joint;
/* print usage message */
void usage(void)
{
printf("GEODOME V%d.%d Geodome generator for POV-Ray V2.n 23-01-94\n", VERSION, INCREMENT);
printf("(C) 1994 Andy Wardley <%s>. All Rights Reserved\n\n", EMAIL_ADDRESS);
printf("usage:\n\tgeodome [-r depth] [-t | -m [-p radius] [-j radius]]\n\n");
printf("\t-r depth recursion depth (default: %i)\n", rec_depth);
printf("\t-t generate triangles (default)\n");
printf("\t-m generate pipe mesh\n");
printf("\t-p radius pipe radius (mesh only) (default: %5.4f)\n", pipe_radius);
printf("\t-j radius joint radius (mesh only) (default: %5.4f)\n", joint_radius);
printf("\nGEODOME may be freely distributed provided it is in its\n");
printf("original form and has not been modified in any way.\n");
}
char *basename(char *pathname)
{
char *ptr;
if ((ptr = strrchr(pathname, '\\')) != NULL)
return ptr + 1;
else
return NULL;
}
/* add a joint to the linked list */
int add_joint(struct vertex *v)
{
struct joint *new_joint, *j;
/* allocate memory for a new joint */
if ((new_joint = (struct joint *) malloc (sizeof(struct joint)))
== (struct joint *) NULL)
{
fprintf(stderr, "Out of memory\n");
return 1;
}
/* load values and set fwd pointer to NULL */
new_joint->v = *v;
new_joint->next = (struct joint *) NULL;
/* check for an empty list */
if (first_joint == (struct joint *) NULL)
first_joint = new_joint;
else
{
j = first_joint;
/* traverse existing linked list */
for (;;)
{
/* forget duplicates */
if (memcmp(&j->v, &new_joint->v, sizeof(struct vertex)) == 0)
{
free(new_joint);
return 0;
}
/* if at end of list, add new joint */
if (j->next == (struct joint *) NULL)
{
j->next = new_joint;
return 0;
}
/* next list element */
j = j->next;
}
}
return 0;
}
/* add an edge to the linked list */
int add_edge(struct vertex *a, struct vertex *b)
{
struct edge *new_edge, *e;
/* allocate memory for a new joint */
if ((new_edge = (struct edge *) malloc(sizeof(struct edge)))
== (struct edge *) NULL)
{
fprintf(stderr, "Out of memory\n");
return 1;
}
/*
load the new structure with the data. We always make sure that
new_edge->a gets the smaller value (reason given below)
*/
if (memcmp(a, b, sizeof(struct vertex)) < 0)
{
new_edge->a = *a;
new_edge->b = *b;
}
else
{
new_edge->a = *b;
new_edge->b = *a;
}
/* set fwd pointer to NULL */
new_edge->next = (struct edge *) NULL;
/* check for an empty linked list */
if (first_edge == (struct edge *) NULL)
first_edge = new_edge;
else
{
e = first_edge;
/* traverse existing linked list */
for (;;)
{
/*
here we compare new element against existing
list elements. If we find a match, we don't
need to add it again. This is why we always
put the smallest value in a, otherwise, we
wouldn't find the match if the ends were swapped.
*/
if (memcmp(&e->a, &new_edge->a, sizeof(struct vertex)) == 0
&& memcmp(&e->b, &new_edge->b, sizeof(struct vertex)) == 0)
{
free(new_edge);
return 0;
}
/* add the edge if we've got to the end of the list */
if (e->next == (struct edge *) NULL)
{
e->next = new_edge;
return 0;
}
/* next list item */
e = e->next;
}
}
return 0;
}
/* add the three joints and edges for a given triangle */
int add_triangle(struct triangle *t)
{
if (add_joint(&t->a) != 0)
return ERROR;
if (add_joint(&t->b) != 0)
return ERROR;
if (add_joint(&t->c) != 0)
return ERROR;
if (add_edge(&t->a, &t->b) != 0)
return ERROR;
if (add_edge(&t->b, &t->c) != 0)
return ERROR;
if (add_edge(&t->c, &t->a) != 0)
return ERROR;
}
/* returns the mid-point of two vertices (extended to geodome radius) */
struct vertex average(struct vertex *v1, struct vertex *v2)
{
struct vertex m;
double hypot, ratio;
m.x = (v1->x + v2->x) / 2;
m.y = (v1->y + v2->y) / 2;
m.z = (v1->z + v2->z) / 2;
hypot = sqrt(pow(m.x, 2) + pow(m.y, 2) + pow(m.z, 2));
ratio = geodome_radius / hypot;
m.x *= ratio;
m.y *= ratio;
m.z *= ratio;
return m;
}
/* sub-divide a triangle into 4 smaller triangles */
void divide_triangle(struct triangle *t, int depth)
{
struct triangle new_t[4];
int subt;
new_t[0].a = t->a;
new_t[1].b = t->b;
new_t[2].c = t->c;
new_t[0].c = new_t[2].a = new_t[3].b = average(&(t->a), &t->c);
new_t[0].b = new_t[1].a = new_t[3].c = average(&t->a, &t->b);
new_t[1].c = new_t[2].b = new_t[3].a = average(&t->c, &t->b);
/* recurse if depth not yet reached */
if (--depth != 0)
for(subt = 0; subt < 4; subt++)
divide_triangle(&new_t[subt], depth);
else
{
/*
dump triangle data or add to linked lists, depending
on the type of geodome
*/
for(subt = 0; subt < 4; subt++)
{
if (mode == TRIANGLE)
printf("\ttriangle {\n\t\t<%.10f, %.10f, %.10f>\
\n\t\t<%.10f, %.10f, %.10f>\n\t\t<%.10f, %.10f, %.10f>\n\t}\n",
new_t[subt].a.x, new_t[subt].a.y, new_t[subt].a.z,
new_t[subt].b.x, new_t[subt].b.y, new_t[subt].b.z,
new_t[subt].c.x, new_t[subt].c.y, new_t[subt].c.z);
else
add_triangle(&new_t[subt]);
}
}
}
void main(int argc, char **argv)
{
char ch;
struct triangle t;
struct joint *j;
struct edge *e;
/* zero linked list */
first_edge = NULL;
first_joint = NULL;
/* read command line */
while ((ch = getopt(argc, argv, "tmr:p:j:")) != EOF)
{
switch(ch)
{
case 't':
mode = TRIANGLE;
break;
case 'm':
mode = MESH;
break;
case 'r':
rec_depth = atoi(optarg);
if (rec_depth == 0)
{
fprintf(stderr, "%s: invalid recursion depth\n",
basename(argv[0]));
exit(1);
}
break;
case 'p':
pipe_radius = atof(optarg);
if (pipe_radius == 0)
{
fprintf(stderr, "%s: invalid pipe radius\n",
basename(argv[0]));
exit(1);
}
break;
case 'j':
joint_radius = atof(optarg);
if (joint_radius == 0)
{
fprintf(stderr, "%s: invalid joint radius\n",
basename(argv[0]));
exit(1);
}
break;
case '?':
usage();
exit(1);
break;
}
}
/* setup the parent triangle */
t.a.x = t.b.x = 0;
t.b.y = t.c.y = 0;
t.a.z = t.c.z = 0;
t.c.x = geodome_radius;
t.a.y = geodome_radius;
t.b.z = geodome_radius;
/* print some stats */
fprintf(stderr, "recursion depth: %i\n", rec_depth);
fprintf(stderr, " mode: %s\n", mode == TRIANGLE ? "triangles" : "mesh");
if (mode == MESH)
{
fprintf(stderr, " pipe radius: %5.4f\n", pipe_radius);
fprintf(stderr, " joint radius: %5.4f\n", joint_radius);
}
printf("/* model data created by geodome V%d.%d */\n", VERSION, INCREMENT);
printf("/* by Andy Wardley <%s> */\n\n", EMAIL_ADDRESS);
printf("#declare geodome_eighth =\nunion {\n");
divide_triangle(&t, rec_depth);
if (mode == MESH)
{
printf("//\tjoints\n");
/* traverse joint list, printing and free as we go */
while (first_joint != (struct joint *) NULL)
{
j = first_joint;
first_joint = first_joint->next;
printf("\tsphere { <%.10f, %.10f, %.10f> %5.4f }\n",
j->v.x, j->v.y, j->v.z, joint_radius);
free(j);
}
printf("\n//\tedges\n");
/* traverse edge list, printing and freeing as we go */
while (first_edge != (struct edge *) NULL)
{
e = first_edge;
first_edge = first_edge->next;
printf("\tcone {\n");
printf("\t\t<%.10f, %.10f, %.10f> %5.4f\n",
e->a.x, e->a.y, e->a.z, pipe_radius);
printf("\t\t<%.10f, %.10f, %.10f> %5.4f\n\t}\n",
e->b.x, e->b.y, e->b.z, pipe_radius);
free(e);
}
}
printf("}\n");
/* finally create some complete geodome hemispheres and spheres */
printf("\n\n#declare geodome_hemisphere = \nunion {\n");
printf("\tobject { geodome_eighth }\n");
printf("\tobject { geodome_eighth rotate <0, 90, 0> }\n");
printf("\tobject { geodome_eighth rotate <0, 180, 0> }\n");
printf("\tobject { geodome_eighth rotate <0, 270, 0> }\n");
printf("}\n");
printf("\n\n#declare geodome = \nunion {\n");
printf("\tobject { geodome_hemisphere }\n");
printf("\tobject { geodome_hemisphere rotate <180, 0, 0> }\n");
printf("}\n");
}